package net.yxsoft.websocket;

import com.alibaba.fastjson.JSON;
import com.jfinal.kit.PropKit;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import net.yxsoft.websocket.component.AttrKeys;
import rapid.core.Authuser;
import rapid.netty.WebSocketServer;
import rapid.netty.WebSocketServerConfig;

import java.util.HashMap;

public class MessageServer extends WebSocketServer {

  private static Channel mainChannel;
  public static MessageServer instance;

  public static final String DOMAIN = PropKit.get("websocket.domain");
  public static final String WebSocketURI = "/websocket";
  public static final int WebSocketPort = PropKit.getInt("websocket.port", 1016);

  public MessageServer(WebSocketServerConfig config) {
    super(config);
  }

  public static void startServer() {
    if(instance == null) {
      WebSocketServerConfig config = new WebSocketServerConfig()
        .address(DOMAIN)
        .port(WebSocketPort)
        .uri(WebSocketURI)
        .heartbeat("HEARTBEAT")
        .commands(CommandsInitializer.register())
        .attr(AttrKeys.ONLINE_USER_MAP, new HashMap<String, Authuser>())
        .attr(AttrKeys.CHANNEL_USER_MAP, new HashMap<ChannelHandlerContext, String>())
        .attr(AttrKeys.USER_CHANNEL_MAP, new HashMap<String, ChannelHandlerContext>());

      instance = new MessageServer(config);
      config.initializer(new MessageServerInitializer(instance.channels(), config));

      instance.start();

      mainChannel = instance.channel;
    }
  }

  public static void stopServer() {
    if(instance != null) {
      instance.destory();
      instance = null;
      mainChannel = null;
    }
  }

  //region 定义全局方法，通过Server类调用

  public static ChannelFuture sendTo(String userId, String content) {
    if(mainChannel == null) {
      return null;
    }

    ChannelHandlerContext ctx = mainChannel.attr(AttrKeys.USER_CHANNEL_MAP).get().get(userId);
    return ctx.writeAndFlush(new TextWebSocketFrame(content));
  }


  public static ChannelFuture sendTo(String userId, Object content) {
    if(mainChannel == null) {
      return null;
    }

    ChannelHandlerContext ctx = mainChannel.attr(AttrKeys.USER_CHANNEL_MAP).get().get(userId);
    return ctx.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(content)));
  }

  public static <T extends Authuser> T getUser(String userId) {
    if(mainChannel == null) {
      return null;
    }

    return (T)mainChannel.attr(AttrKeys.ONLINE_USER_MAP).get().get(userId);
  }

  public static void saveUser(Authuser user) {
    if(mainChannel == null) {
      return;
    }

    mainChannel.attr(AttrKeys.ONLINE_USER_MAP).get().put(user.getId(), user);
  }



  public static void addUser(String userId, ChannelHandlerContext ctx) {
    if(mainChannel == null) {
      return;
    }

    HashMap<String, ChannelHandlerContext> cp1 = mainChannel.attr(AttrKeys.USER_CHANNEL_MAP).get();
    if(!cp1.containsKey(userId)) {
      cp1.put(userId, ctx);
    }


    HashMap<ChannelHandlerContext, String> cp2 = mainChannel.attr(AttrKeys.CHANNEL_USER_MAP).get();
    if(!cp2.containsKey(ctx)) {
      cp2.put(ctx, userId);
    }
  }

  public static boolean addUserCtx(ChannelHandlerContext ctx, String userId) {
    if(mainChannel == null) {
      return false;
    }

    HashMap<ChannelHandlerContext, String> cp = mainChannel.attr(AttrKeys.CHANNEL_USER_MAP).get();
    if(!cp.containsKey(ctx)) {
      cp.put(ctx, userId);
      return true;
    }

    return false;
  }

  public static String getUserId(ChannelHandlerContext ctx) {
    if(mainChannel == null) {
      return "";
    }

    return mainChannel.attr(AttrKeys.CHANNEL_USER_MAP).get().get(ctx);
  }




  public static ChannelHandlerContext getUserCtx(String userId) {
    if(mainChannel == null) {
      return null;
    }

    return mainChannel.attr(AttrKeys.USER_CHANNEL_MAP).get().get(userId);
  }



  public static void removeUser(ChannelHandlerContext ctx) {
    if(mainChannel == null) {
      return;
    }

    String userId = mainChannel.attr(AttrKeys.CHANNEL_USER_MAP).get().get(ctx);

    if(ctx != null) {
      mainChannel.attr(AttrKeys.CHANNEL_USER_MAP).get().remove(ctx);
    }

    mainChannel.attr(AttrKeys.USER_CHANNEL_MAP).get().remove(userId);

    mainChannel.attr(AttrKeys.ONLINE_USER_MAP).get().remove(userId);
  }




  public static void removeUser(String userId) {
    if(mainChannel == null) {
      return;
    }

    ChannelHandlerContext ctx = mainChannel.attr(AttrKeys.USER_CHANNEL_MAP).get().get(userId);

    if(ctx != null) {
      mainChannel.attr(AttrKeys.CHANNEL_USER_MAP).get().remove(ctx);
    }

    mainChannel.attr(AttrKeys.USER_CHANNEL_MAP).get().remove(userId);

    mainChannel.attr(AttrKeys.ONLINE_USER_MAP).get().remove(userId);
  }


  public static boolean addUserId(String userId, ChannelHandlerContext ctx) {
    if(mainChannel == null) {
      return false;
    }

    HashMap<String, ChannelHandlerContext> cp = mainChannel.attr(AttrKeys.USER_CHANNEL_MAP).get();
    if(!cp.containsKey(userId)) {
      cp.put(userId, ctx);
      return true;
    }

    return false;
  }

  //endregion
}
